package study.test.demo.dom4j;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.ElementHandler;
import org.dom4j.ElementPath;
import org.dom4j.io.SAXReader;

import lombok.extern.slf4j.Slf4j;

/**
 * dom4j处理大数据
 * 
 * @ClassName XmlUtil
 * @author <a href="892042158@qq.com" target="_blank">于国帅</a>
 * @date 2018年4月17日 上午9:58:56
 *
 */
@Slf4j
public class Dom4jXmlUtil {
    private static final SAXReader READER_DOM = new SAXReader();
    private static SAXReader READER_NODE = new SAXReader();
    private static final int MB = 1048576;

    /**
     * 
     * @Title read
     * @author 于国帅
     * @date 2018年4月17日 上午9:23:29
     * @throws DocumentException
     * @throws FileNotFoundException
     *             void
     */
    public static List<List<String>> readList(String filePath, String rowElementName) {
        List<List<String>> dataList = new ArrayList<>();
        READER_NODE.setDefaultHandler(new ElementHandler() {
            List<String> rowList = null;

            public void onEnd(ElementPath ep) {
                Element e = ep.getCurrent(); // 获得当前节点
                // 符合当前元素的进行筛选
                if (e.getName().equals(rowElementName)) {
                    List<Element> eleList = e.elements();
                    if (CollectionUtils.isNotEmpty(eleList)) {
                        rowList = new LinkedList<>();
                        for (Element ele : eleList) {
                            rowList.add(String.valueOf(ele.getText()));
                        }
                        dataList.add(rowList);
                    }
                    e.detach(); // 记得从内存中移去
                }
            }

            public void onStart(ElementPath arg0) {

            }
        });
        try {
            READER_NODE.read(new BufferedInputStream(new FileInputStream(new File(filePath))));
        } catch (Exception e) {
            log.error("readList", e);
            return null;
        }
        return dataList;
    }

    /**
     * 读取所有的数据并且转换
     * 
     * @Title readMap
     * @author 于国帅
     * @date 2018年4月16日 下午3:00:45
     * @param filePath
     * @param rowElementName
     * @return
     * @throws DocumentException
     *             Map<String,Object>
     * @throws FileNotFoundException
     */
    public static Map<String, Object> readMapEnvent(String filePath, String rowElementName) {
        // 需要增加判断是否节点很大，很大会报内存溢出
        List<Map<String, Object>> dataList = new ArrayList<>();
        READER_NODE.setDefaultHandler(new ElementHandler() {
            Map<String, Object> map = new LinkedHashMap<>();
            boolean endFlag = true; // 暂时读取数据到内存后再移除，后期处理为读取到了标题后不再读取

            public void onEnd(ElementPath ep) {
                Element e = ep.getCurrent(); // 获得当前节点
                if (endFlag) {
                    // 符合当前元素的进行筛选
                    if (e.getName().equals(rowElementName)) {
                        List<Element> eleList = e.elements();
                        if (CollectionUtils.isNotEmpty(eleList)) {
                            for (Element ele : eleList) {
                                map.put(ele.getName(), ele.getText());
                            }
                            dataList.add(map);
                            endFlag = false;
                        }
                        e.detach(); // 内存中移去
                    }
                } else {
                    e.detach(); // 读取完标题后后面的数据不再读取
                }
            }

            public void onStart(ElementPath arg0) {

            }
        });
        try {
            READER_NODE.read(new BufferedInputStream(new FileInputStream(new File(filePath))));
        } catch (Exception e) {
            log.error("readMapEnvent", e);
            return null;
        }
        return dataList.size() > 0 ? dataList.get(0) : null;
    }

    /**
     * 读取所有的数据并且转换
     * 
     * @Title readMap
     * @author 于国帅
     * @date 2018年4月16日 下午3:00:45
     * @param filePath
     * @param rowElementName
     * @return
     * @throws DocumentException
     *             Map<String,Object>
     * @throws FileNotFoundException
     */
    @Deprecated
    public static Map<String, Object> readMap1(String filePath, String rowElementName) {
        Map<String, Object> map = new HashMap<>();
        Document doc;
        try {
            doc = READER_DOM.read(new File(filePath));
            // 获取根元素
            Element root = doc.getRootElement();
            // 获取根元素中 单挑元素进行处理
            List<Element> rowList = root.elements(rowElementName);
            if (CollectionUtils.isNotEmpty(rowList)) {
                Element rowEle = rowList.get(0);
                List<Element> eleList = rowEle.elements();
                if (CollectionUtils.isNotEmpty(eleList)) {
                    for (Element ele : eleList) {
                        map.put(ele.getName(), ele.getText());
                    }
                }
            }
        } catch (Exception e) {
            log.error("readMap", e);
            return null;
        }
        return map;
    }

    /**
     * 以nio的方式读取 标题
     * 
     * @param filePath
     * @param rowElementName
     * @return
     */
    public static Map<String, Object> readMap(String filePath, String rowElementName) {
        try {
            ChannelFileReader channelFileReader = new ChannelFileReader(filePath, 1 * MB, rowElementName);
            while (channelFileReader.read() != -1)
                ; // 优化为对非法节点的处理
//            channelFileReader.read(); // 暂时只读取1次
            return channelFileReader.getTitleMap();
        } catch (Exception e) {
            log.error("readMap", e);
            return null;
        }
    }
}
